#
# The interrupts.s file provides entry points for ISRs
#

# Reference to the general-purpose exception handling function
.extern common_exception

# Reference to current process structure (defined in scheduler.c)	
.extern	current_process
# Reference to System's TSS esp0 field (defined in i386_pmode.c)
.extern tss_esp0
# reference to kernel re-entering counter (globals.c)
.extern kernel_entering_count

.extern show_message
	
#
#   Exceptions Classification (Section 5-5 of Intel manual)
#
#   - Faults: can be corrected, program can restart without loss of continuity. CS:EIP points to the instruction causing the fault.
#   - Traps: is reported immediately after the executing of the trapping instruction. CS:EIP points to the instruction after the one cauisng the trap.
#   - Aborts: Does not report the exact location of the instruction, dies dot allow restart of the task. Used to report severe errors/illegal values in system tables.
#



# 
#   These routines are ISRs to serve interrupts generated by the i386+ processor 
#   Note: Name, Vector, Mnemonic and Type information is taken from Intel's manual
#


#   Name: Divide Error
#   Vector: 0
#   Mnemonic: #DE
#   Type: Fault
#
.global	isr_divide
isr_divide:
	cli
	pushl	$0		# Push error code
	pushl	$0		# Push interrupt number
	jmp	isr_all_ints
		

#   Name: Debug
#   Vector: 1
#   Mnemonic: #DB
#   Type: Fault/Trap
#
.global isr_debug
isr_debug:
	cli
	pushl	$0		# Push error code
	pushl	$1		# Push interrupt number
	jmp	isr_all_ints

	
#   Name: NMI Interrupt
#   Vector: 2
#   Mnemonic: --
#   Type: Interrupt
#
.global isr_nmi
isr_nmi:
	cli
	pushl	$0		# Push error code
	pushl	$2		# Push interrupt number
	jmp	isr_all_ints
	
		

#   Name: Breakpoint
#   Vector: 3
#   Mnemonic: #BP
#   Type: Trap
# 
.global isr_breakpoint
isr_breakpoint:
	cli
	pushl	$0		# Push error code
	pushl	$3		# Push interrupt number
	jmp	isr_all_ints


	
#   Name: Overflow
#   Vector: 4
#   Mnemonic: #OF
#   Type: Trap
# 
.global isr_overflow
isr_overflow:
	cli
	pushl	$0		# Push error code
	pushl	$4		# Push interrupt number
	jmp	isr_all_ints



#   Name: BOUND Range Exceeded
#   Vector: 5
#   Mnemonic: #BR
#   Type: Fault
#
.global isr_bound
isr_bound:
	cli
	pushl	$0		# Push error code
	pushl	$5		# Push interrupt number
	jmp	isr_all_ints



#   Name: Invalid Opcode (Undefined Opcode)
#   Vector: 6
#   Mnemonic: #UD
#   Type: Fault
# 
.global isr_opcode
isr_opcode:
	cli
	pushl	$0		# Push error code
	pushl	$6		# Push interrupt number
	jmp	isr_all_ints



#   Name: Device Not Available (No Math Coprocessor)
#   Vector: 7
#   Mnemonic: #NM
#   Type: Fault
#
.global isr_nofpu
isr_nofpu:
	cli
	pushl	$0		# Push error code
	pushl	$7		# Push interrupt number
	jmp	isr_all_ints



#   Name: Double Fault
#   Vector: 8
#   Mnemonic: #DF
#   Type: Abort -- pushes err code (always 0)
#
.global isr_doublefault
isr_doublefault:
	cli
				# CPU pushes error code
	pushl	$8		# Push interrupt number
	jmp	isr_all_ints
	 

#   Name: Coprocessor Segment Overrun (reserved)
#   Vector: 9
#   Mnemonic: --
#   Type: Fault
# 
.global isr_fpuoverrun
isr_fpuoverrun:
	cli
	pushl	$0		# Push error code
	pushl	$9		# Push interrupt number
	jmp	isr_all_ints



#   Name: Invalid TSS
#   Vector: 10
#   Mnemonic: #TS
#   Type: Fault -- pushes err code
# 
.global isr_invalidtss
isr_invalidtss:
	cli
				# CPU pushes error code
	pushl	$10		# Push interrupt number
	jmp	isr_all_ints

	

#   Name: Segment Not Present
#   Vector: 11
#   Mnemonic: #NP
#   Type: Fault -- pushes err code
#
.global isr_nosegment
isr_nosegment:
	cli
				# CPU pushes error code
	pushl	$11		# Push interrupt number
	jmp	isr_all_ints


#   Name: Stack-Segment Fault
#   Vector: 12
#   Mnemonic: #SS
#   Type: Fault -- pushes err code
# 
.global isr_stacksegment
isr_stacksegment:
	cli
				# CPU pushes error code
	pushl	$12		# Push interrupt number
	jmp	isr_all_ints


#   Name: General Protection Fault
#   Vector: 13
#   Mnemonic: #GP
#   Type: Fault -- pushes err code
# 
.global isr_gpf
isr_gpf:
	cli
				# CPU pushes error code
	pushl	$13		# Push interrupt number
	jmp	isr_all_ints


#   Name: Page Fault
#   Vector: 14
#   Mnemonic: #PF
#   Type: Fault -- pushes err code
#
.global isr_pagefault
isr_pagefault:
	cli
				# CPU pushes error code
	pushl	$14		# Push interrupt number
	jmp	isr_all_ints
 


#   Name: (Intel reserved)
#   Vector: 15
#   Mnemonic: --
#   Type: --
# 


#   Name: x87 FPU Floating-Point Error (Math Fault)
#   Vector: 16
#   Mnemonic: #MF
#   Type: Fault
# 
.global isr_mathfault
isr_mathfault:
	cli
	pushl	$0		# Push error code
	pushl	$16		# Push interrupt number
	jmp	isr_all_ints


#   Name: Alignment Check
#   Vector: 17
#   Mnemonic: #AC
#   Type: Fault
#
.global isr_alignment
isr_alignment:
	cli
	pushl	$0		# Push error code
	pushl	$17		# Push interrupt number
	jmp	isr_all_ints
	 

#   Name: Machine Check
#   Vector: 18
#   Mnemonic: #MC
#   Type: Abort
#
.global isr_machine
isr_machine:
	cli
	pushl	$0		# Push error code
	pushl	$18		# Push interrupt number
	jmp	isr_all_ints
 

#   Name: SIMD Floating-Point Exception
#   Vector: 19
#   Mnemonic: #XF
#   Type: Fault
#
.global isr_fpesimd
isr_fpesimd:
	cli
	pushl	$0		# Push error code
	pushl	$19		# Push interrupt number
	jmp	isr_all_ints
 

# Extra ISRs to handle other types of interrupts 


#   Name: (reserved)
#   Vector: --
#   Mnemonic: --
#   Type: Trap
#
#.global isr_reserved
#isr_reserved:
#	cli	
#	pushl	$0		# Push error code
#	pushl	$20		# Push interrupt number (use the first reserved one)
#	jmp	isr_all_ints
	 


#   Name: (unhandled interrupt)
#   Vector: --
#   Mnemonic: --
#   Type: Trap
#
.global isr_unhandled
isr_unhandled:
	cli
	pushl	$0		# Push error code
	pushl	$33		# Push interrupt number (use the first one after syscall)
	jmp	isr_all_ints
	

# ==================================================
# MANAGE IRQs
# ==================================================

.global isr_irq_00
isr_irq_00:
	cli
	pushl	$0		# Push error code
	pushl	$48		# Push interrupt number
	jmp	isr_all_ints
	
.global isr_irq_01
isr_irq_01:
	cli
	pushl	$0		# Push error code
	pushl	$49		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_02
isr_irq_02:
	cli
	pushl	$0		# Push error code
	pushl	$50		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_03
isr_irq_03:
	cli
	pushl	$0		# Push error code
	pushl	$51		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_04
isr_irq_04:
	cli
	pushl	$0		# Push error code
	pushl	$52		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_05
isr_irq_05:
	cli
	pushl	$0		# Push error code
	pushl	$53		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_06
isr_irq_06:
	cli
	pushl	$0		# Push error code
	pushl	$54		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_07
isr_irq_07:
	cli
	pushl	$0		# Push error code
	pushl	$55		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_08
isr_irq_08:
	cli
	pushl	$0		# Push error code
	pushl	$56		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_09
isr_irq_09:
	cli
	pushl	$0		# Push error code
	pushl	$57		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_10
isr_irq_10:
	cli
	pushl	$0		# Push error code
	pushl	$58		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_11
isr_irq_11:
	cli
	pushl	$0		# Push error code
	pushl	$59		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_12
isr_irq_12:
	cli
	pushl	$0		# Push error code
	pushl	$60		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_13
isr_irq_13:
	cli
	pushl	$0		# Push error code
	pushl	$61		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_14
isr_irq_14:
	cli
	pushl	$0		# Push error code
	pushl	$62		# Push interrupt number
	jmp	isr_all_ints

.global isr_irq_15
isr_irq_15:
	cli
	pushl	$0		# Push error code
	pushl	$63		# Push interrupt number
	jmp	isr_all_ints

	
# ==================================================
# Common ISR
# ==================================================
	
# Common routine for all interrupts (byte_t int_num, dword_t err_code)
isr_all_ints:
	# we save the context here to allow for a later process-switch
	cld	
	pushl	%gs                      # push segment registers (+4 dwords)
	pushl	%fs
	pushl	%es
	pushl	%ds
        pushal                           # push GP registers (+8 dwords)
	
	movl	$0x10,%eax		 # 0x10 is SYSTEM_DATA selector
	movl	%eax,%ds		 # put known-good values in seg regs
	movl	%eax,%es
	movl	%eax,%fs
	movl	%eax,%gs

	incl	(kernel_entering_count)

	# If we're re-entering do not save user-process kernel stack value
	cmpl	$1,(kernel_entering_count)
	je	0f

	movl	current_process,%eax	 # Point to current process
	movl	%esp,%ebx		 # Save current stack pointer in EBX
	movl	%ebx,(%eax)		 # Save kernel stack top

0:
	pushl	%esp			 # push pointer to stacked regs_t
	call	common_exception	 # call C language handler
	cli				 # might have been enabled before
        popl	%eax			 # drop pointer to stacked regs_t


	# If we're re-entering do not restore user-process kernel stack value
	# and do not modify TSS.esp0
	cmpl	$1,(kernel_entering_count)
	je	1f
	
	movl	current_process,%eax	 # Point to current process
	movl	(%eax),%ebx		 # Get kernel stack top
	movl	%ebx,%esp		 # Switch to new process' kernel stack

	# Update TSS.esp0 for next kernel mode switch
	movl	tss_esp0,%eax		
	addl	$76,%ebx		# 19 dwords == 76 bytes
	movl	%ebx,(%eax)		# Ring 0 ESP value after IRET

1:
        popal                            # pop GP registers (-8 dwords)
	popl	%ds                      # pop segment registers (-4 dwords)
	popl	%es
	popl	%fs
	popl	%gs
	
	addl	$8,%esp                  # drop exception number and
					 # error code (-2 dwords)

	decl	(kernel_entering_count)
		
	iret                             # IRET pops IP, CS, EFLAGS, ESP, SS
					 # (-5 dwords)
			
	
# This is the syscall ISR... 

#   Name: Syscall Interrupt
#   Vector: #SYSCALL_VECTOR
#   Mnemonic: --
#   Type: Trap
#
.global isr_syscall
isr_syscall:
	cli
	pushl	$0		# Push error code
	pushl	$32		# Push interrupt number (syscall)
	jmp	isr_all_ints

# Simulate a return to user mode process	
.global start_multitasking	
start_multitasking:
	popl	%eax			 # discard eip
	
	movl	current_process,%eax	 # Point to current process
	movl	(%eax),%ebx		 # Get kernel stack top
	movl	%ebx,%esp		 # Switch to new process' kernel stack

	# Update TSS.esp0 for next kernel mode switch
	movl	tss_esp0,%eax
	addl	$76,%ebx
	movl	%ebx,(%eax)		
	
        popal                            # pop GP registers (-8 dwords)
	popl	%ds                      # pop segment registers (-4 dwords)
	popl	%es
	popl	%fs
	popl	%gs

	addl	$8,%esp                  # drop exception number and
					 # error code (-2 dwords)
	
	iret                             # IRET pops IP, CS, EFLAGS, ESP, SS
